package com.pig4cloud.pig.common.file.local;

import cn.hutool.core.io.FileUtil;
import com.pig4cloud.pig.common.file.core.FileProperties;
import com.pig4cloud.pig.common.file.core.FileTemplate;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

/**
 * 本地文件存储模板实现
 * <p>
 * 实现FileTemplate接口，提供基于本地文件系统的存储服务
 * </p>
 *
 * @author lengleng
 * @date 2022/4/19
 */
@RequiredArgsConstructor
public class LocalFileTemplate implements FileTemplate {

	/**
	 * 文件配置属性
	 */
	private final FileProperties properties;

	/**
	 * 简单的Bucket数据对象
	 * @param name 存储桶名称
	 */
	public record SimpleBucket(String name) {

	}

	/**
	 * 简单的对象摘要数据
	 * @param key 对象键名
	 */
	public record SimpleObjectSummary(String key) {

	}

	/**
	 * 创建Bucket存储桶
	 * <p>
	 * 在本地文件系统中创建对应的目录
	 * </p>
	 * @param bucketName 存储桶名称
	 */
	@Override
	public void createBucket(String bucketName) {
		FileUtil.mkdir(properties.getLocal().getBasePath() + FileUtil.FILE_SEPARATOR + bucketName);
	}

	/**
	 * 获取所有Bucket列表
	 * <p>
	 * 遍历基础路径下的所有目录作为Bucket
	 * </p>
	 * @return Bucket列表
	 */
	@Override
	public List<SimpleBucket> getAllBuckets() {
		return Arrays.stream(FileUtil.ls(properties.getLocal().getBasePath()))
			.filter(FileUtil::isDirectory)
			.map(dir -> new SimpleBucket(dir.getName()))
			.toList();
	}

	/**
	 * 删除指定Bucket
	 * <p>
	 * 删除对应的本地目录及其内容
	 * </p>
	 * @param bucketName 存储桶名称
	 */
	@Override
	public void removeBucket(String bucketName) {
		FileUtil.del(properties.getLocal().getBasePath() + FileUtil.FILE_SEPARATOR + bucketName);
	}

	/**
	 * 上传文件
	 * <p>
	 * 将文件流保存到本地文件系统，如果Bucket不存在则自动创建
	 * </p>
	 * @param bucketName 存储桶名称
	 * @param objectName 对象名称（文件名）
	 * @param stream 文件输入流
	 * @param contextType 文件MIME类型（本地存储未使用）
	 */
	@Override
	public void putObject(String bucketName, String objectName, InputStream stream, String contextType) {
		// 当 Bucket 不存在时创建
		String dir = properties.getLocal().getBasePath() + FileUtil.FILE_SEPARATOR + bucketName;
		if (!FileUtil.isDirectory(properties.getLocal().getBasePath() + FileUtil.FILE_SEPARATOR + bucketName)) {
			createBucket(bucketName);
		}

		// 写入文件
		File file = FileUtil.file(dir + FileUtil.FILE_SEPARATOR + objectName);
		FileUtil.writeFromStream(stream, file);
	}

	/**
	 * 获取文件
	 * <p>
	 * 从本地文件系统读取文件并返回输入流
	 * </p>
	 * @param bucketName 存储桶名称
	 * @param objectName 对象名称（文件名）
	 * @return 文件输入流
	 */
	@Override
	@SneakyThrows
	public InputStream getObject(String bucketName, String objectName) {
		String dir = properties.getLocal().getBasePath() + FileUtil.FILE_SEPARATOR + bucketName;
		return FileUtil.getInputStream(dir + FileUtil.FILE_SEPARATOR + objectName);
	}

	/**
	 * 删除指定存储桶中的对象
	 * <p>
	 * 从本地文件系统删除指定文件
	 * </p>
	 * @param bucketName 存储桶名称
	 * @param objectName 对象名称
	 * @throws Exception 删除过程中可能抛出的异常
	 */
	@Override
	public void removeObject(String bucketName, String objectName) throws Exception {
		String dir = properties.getLocal().getBasePath() + FileUtil.FILE_SEPARATOR + bucketName;
		FileUtil.del(dir + FileUtil.FILE_SEPARATOR + objectName);
	}

	/**
	 * 上传文件到指定存储桶
	 * <p>
	 * 自动检测文件类型的上传方法
	 * </p>
	 * @param bucketName 存储桶名称
	 * @param objectName 对象名称（文件名）
	 * @param stream 文件输入流
	 * @throws Exception 上传过程中可能发生的异常
	 */
	@Override
	public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
		putObject(bucketName, objectName, stream, null);
	}

	/**
	 * 根据前缀查询文件
	 * <p>
	 * 在指定存储桶中查找以指定前缀开头的文件
	 * </p>
	 * @param bucketName 存储桶名称
	 * @param prefix 文件名前缀
	 * @param recursive 是否递归查询（本地存储未实现）
	 * @return 文件对象摘要列表
	 */
	@Override
	public List<SimpleObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
		String dir = properties.getLocal().getBasePath() + FileUtil.FILE_SEPARATOR + bucketName;

		return Arrays.stream(FileUtil.ls(dir))
			.filter(file -> file.getName().startsWith(prefix))
			.map(file -> new SimpleObjectSummary(file.getName()))
			.toList();
	}

}
